﻿#pragma once

#include "Misc/EngineEditorMacros.h"
#include "Object/Object.h"
#include "Math/Color.h"
#include "Math/Vec2.h"
#include "MaterialGraph/UndoRedo/MaterialEditOperation.h"
#include "MaterialGraph/Node/MaterialGraphNodeModel.h"
#include "Containers/Any.h"
#include "MaterialGraphNodeViewModel.m.h"

class CProperty;
class RMaterialGraphNodeModel;
class RMaterialGraphViewModel;
class RMaterialGraphPinViewModel;
class RMaterialGraphModel;

RCLASS()
class RMaterialGraphNodeViewModel : public RObject
{
    ROBJECT

public:
    virtual void BindModel(
        TSharedObjectPtr<RMaterialGraphNodeModel> InModel
        , TSharedObjectPtr<RMaterialGraphViewModel> InGraph
        ) ;

    const float LineHorizontalPadding = 15.0f;
    const float LineVerticalPadding = 5.0f;
    const float LineHeight = 20.0f;
    const float BackgroundRadius = 5.0f;
    const SColor BackgroundColor = SColor::FromHexRGB(0x303030);

    TSharedObjectPtr<RMaterialGraphViewModel> GetGraphViewModel() const;
    float GetScale() const;
    //in graph space
    SVec2 GetGraphOffset() const;
    float GetNodeX() const;
    float GetNodeY() const;
    void SetNodePosition(const SVec2 & InPos);

    //get node X in graph widget space
    float GetNodeWidgetSpaceX() const;
    //get node Y in graph widget space
    float GetNodeWidgetSpaceY() const;

    //get widget Y of line in node widget
    float GetLineY(int64_t Index) const;

    bool IsSelected() const;

    virtual float GetNodeWidth() const { return 200.0f; }
    float GetNodeHeight() const;
    virtual SColor GetTitleBackgroundColor() const { return SColor::FromHexRGB(0x83314A); }
    SColor GetOutputNodeTitleBackgroundColor () const;
    virtual int64_t GetLineNum() const { return 5; }
    virtual CString GetName() const { return U"未命名"; };
    //这个节点是否是参数节点或者可以转变成参数节点
    virtual bool PotentiallyIsOrIsParameter() const { return false; }
    virtual bool IsParameter() const { return false; }
    virtual void ToggleParameter() { };
    virtual CString GetParameterName() const { return U""; }
    virtual void SetParameterName(const CString & InName) { }

    //invoked when Line number/line content changed
    TDelegate<void> OnNodeLineChanged;

    int64_t GetInputNum() const;
    TSharedObjectPtr<RMaterialGraphPinViewModel> GetInput(int64_t Index) const;
    virtual CString GetInputPinName(int64_t Index) const { return U"输入"; }
    float GetInputDefaultX(int64_t Index) const;
    void SetInputDefaultX(int64_t Index, float InValue);

    float GetInputDefaultY(int64_t Index) const;
    void SetInputDefaultY(int64_t Index, float InValue);

    float GetInputDefaultZ(int64_t Index) const;
    void SetInputDefaultZ(int64_t Index, float InValue);

    int64_t GetOutputNum() const;
    TSharedObjectPtr<RMaterialGraphPinViewModel> GetOutput(int64_t Index) const;
    virtual CString GetOutputPinName(int64_t Index) const { return U"输出"; }

    void OnPinDragStarted(TSharedObjectPtr<RMaterialGraphPinViewModel> InPin);
    void OnPinDragEnded(TSharedObjectPtr<RMaterialGraphPinViewModel> InPin);

    void SelectThisNode();

    TSharedObjectPtr<RMaterialGraphNodeModel> GetBaseNodeModel() const;
protected:
    TWeakObjectPtr<RMaterialGraphNodeModel> BaseNodeModel;
    TWeakObjectPtr<RMaterialGraphViewModel> GraphViewModel;

    TVector<TSharedObjectPtr<RMaterialGraphPinViewModel>> InputViewModels;
    TVector<TSharedObjectPtr<RMaterialGraphPinViewModel>> OutputViewModels;
};

//the operation to move the node
RCLASS()
class RMaterialMoveNodeOperation : public RMaterialEditOperation
{
    ROBJECT

public:

    RFIELD()
    TSharedObjectPtr<RMaterialGraphNodeModel> Node;

    SVec2 OldPosition;

    SVec2 NewPosition;

    virtual void Undo(TSharedObjectPtr<RMaterialGraphModel> InGraph) override;
    virtual void Redo(TSharedObjectPtr<RMaterialGraphModel> InGraph) override;
    virtual bool CombineTo(TSharedObjectPtr<RMaterialEditOperation> InFormerOperation) override;
};

